c# Winform 多线程操作

您所在的位置:网站首页 winform 爬虫 c# Winform 多线程操作

c# Winform 多线程操作

2023-09-03 00:56| 来源: 网络整理| 查看: 265

主要是对一个过程需要的时间很长执行时会出现界面假死的情况

方法1:

Application.DoEvents(),这种方法当你拖动窗体时,界面不会假死。但在你拖动时代码不再执行,也就是阻塞了,当你不再控制窗体时会继续执行,其实这还是一个单线程

for (int i = 0; i < 10000; i++) { for (int j = 0; j < 100000; j++) { textBox1.Text = i.ToString() + " " + j.ToString(); Application.DoEvents(); } }

 

方法2:多线程

       2.1:取消控件跨线程检测(不推荐有时会出现一些莫名奇妙的错误如控件不能加载等问题)

               2.1.1取消窗体内控件的跨线程检查(单个控件取消也可以)    

public Form1() { InitializeComponent(); CheckForIllegalCrossThreadCalls = false;//干掉检测 不再检测跨线程 }

               2.1.2新建线程实现跨线程访问

/// /// 新建线程并执行 /// /// /// private void button1_Click(object sender, EventArgs e) { ThreadStart thStart = new ThreadStart(Pro);//threadStart委托 Thread thread = new Thread(thStart); thread.Priority = ThreadPriority.Highest; thread.IsBackground = true; //关闭窗体继续执行 thread.Start(); } public void Pro() { for (int i = 0; i < 10000; i++) { for (int j = 0; j < 100000; j++) { textBox1.Text = j.ToString(); } } }

 

       2.2:主线程中操作(推荐)

    2.2.1 不用取消跨线程访问

/// /// 新建线程并执行 /// /// /// private void button1_Click(object sender, EventArgs e) { ThreadStart thStart = new ThreadStart(Pro);//threadStart委托 Thread thread = new Thread(thStart); thread.Priority = ThreadPriority.Highest; thread.IsBackground = true; //关闭窗体继续执行 thread.Start(); } public void Pro() { for (int i = 0; i < 10000; i++) { for (int j = 0; j < 100000; j++) { if (textBox1.InvokeRequired)//不同线程访问了 textBox1.Invoke(new Action(SetTxtValue), textBox1, j.ToString());//跨线程了 else//同线程直接赋值 textBox1.Text = j.ToString(); } } } private void SetTxtValue(TextBox txt, string value) { txt.Text = value; }

 注:多个线程同时访问一个方法时 需要锁定

public static readonly object obj = new object(); public void Pro() { //lock(obj){}=Monitor.Enter(obj) Monitor.Exit(obj) lock (obj) { for (int i = 0; i < 10000; i++) { for (int j = 0; j < 100000; j++) { if (textBox1.InvokeRequired)//不同线程访问了 textBox1.Invoke(new Action(SetTxtValue),                       textBox1, j.ToString());//跨线程了 else//同线程直接赋值 textBox1.Text = j.ToString(); } } } }

 

3.窗体与自定义类之间的多线程操作(适用数据量大查询速度慢时 让数据在新线程中查询 防主线程卡死)

     3.1自定义类中定义事件,并定义各事件执行的步骤方法

     3.2窗体中实现类,并生成类各事件,在多线程中执行自定义类的步骤方法

     3.3 代码3.1

public class WeiTuo { public int count { get; set; } public event EventHandler StartEvent; public event EventHandler MidEvent; public event EventHandler EndEvent; public event EventHandler EEvent; public void ExecEvent() { try { using (SqlConnection con = new SqlConnection("server=.;uid=sa;pwd=123;database=oa")) { using (SqlDataAdapter adp = new SqlDataAdapter("select * from a", con)) { DataTable dt = new DataTable(); adp.Fill(dt); StartEvent(dt.Rows.Count, null); for (int i = 0; i < dt.Rows.Count; i++) { a ai = new a() { ID = (int)dt.Rows[i]["id"], Code = dt.Rows[i]["cCode"].ToString() } ; MidEvent(ai, null); } EndEvent(dt.Rows.Count, null); } } } catch (Exception e) { EEvent(e.Message, null); } } } public class a { public int ID { get; set; } public String Code { get; set; } = ""; } View Code

    3.4 代码3.2

private void button6_Click(object sender, EventArgs e) { WeiTuo wt = new WeiTuo(); wt.StartEvent += Wt_StartEvent; wt.MidEvent += Wt_MidEvent; wt.EndEvent += Wt_EndEvent; wt.EEvent += Wt_EEvent; Thread th = new Thread(wt.ExecEvent); th.Start(); } //特殊委托 action private void Wt_StartEvent(object sender, EventArgs e) { Action setLVItem = (s) => { listView1.Items.Add(s); }; this.Invoke(setLVItem, sender.ToString()); } //特殊委托 action private void Wt_MidEvent(object sender, EventArgs e) { Action setLVItem = (s) => { listView1.Items.Add(s); }; this.Invoke(setLVItem, ((a)sender).Code); } #region 委托实现 private void Wt_EndEvent(object sender, EventArgs e) { this.Invoke(new setLVItem(setEndValue), "成功"); } delegate void setLVItem(string s); void setEndValue(string s) { MessageBox.Show(s); } #endregion private void Wt_EEvent(object sender, EventArgs e) { Action ShowBox = (s) => { MessageBox.Show(s); }; this.Invoke(ShowBox, sender.ToString()); } View Code

   3.5 结果如下图

 

task任务与thread大同小异

使用时 尽量少的让控件跨线程 可通过ref 或 out 对参数传出 检测线程结束 再给控件赋值 

也可用task的wait方法

4 异步回调

private void button1_Click(object sender, EventArgs e) { Func Sum = (i, j) => { Thread.Sleep(3000); return i + j; }; listView1.Items.Add("开始"); IAsyncResult iar = Sum.BeginInvoke(1, 2, CallbackWhenDone, "我是测试"); listView1.Items.Add("over"); } private void CallbackWhenDone(IAsyncResult iar) { AsyncResult ar = (AsyncResult)iar; Func f = (Func)ar.AsyncDelegate; Action a = (lv) => { lv.Items.Add(ar.AsyncState.ToString()); lv.Items.Add(f.EndInvoke(iar).ToString()); }; this.Invoke( a,listView1); } View Code

 



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3